/**************************************************************************
 * This file is property of and copyright by the ALICE HLT Project        *
 * ALICE Experiment at CERN, All rights reserved.                         *
 *                                                                        *
 * Primary Authors: Artur Szostak <artursz@iafrica.com>                   *
 *                  for The ALICE HLT Project.                            *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/**
 * @file   testAliHLTTPCDataCheckerComponent.C
 * @author Artur Szostak <artursz@iafrica.com>
 * @date   9 Aug 2010
 *
 * This macro is used to test the basic functionality of the
 * AliHLTTPCDataCheckerComponent class.
 */

#if !defined(__CINT__) || defined(__MAKECINT__)
#include "Riostream.h"
#include "TSystem.h"
#include "TClassTable.h"
#include "AliLog.h"
#include "AliHLTSystem.h"
#include "AliHLTConfiguration.h"
#include <fstream>
#include <cstdlib>
#endif

/**
 * Creates the input data for the test.
 * It is just a file of 256 bytes with all zeros.
 */
void GenerateInputData(bool debug = false)
{
	using namespace std;
	const char* filename = "dataCheckerInputTestFile.dat";
	fstream file(filename, ios::trunc | ios::out | ios::binary);
	if (! file)
	{
		if (debug) cerr << "ERROR: Could not create file " << filename << endl;
		return;
	}
	
	char buffer[256];
	memset(buffer, 0x0, sizeof(buffer));
	AliHLTUInt32_t* words = reinterpret_cast<AliHLTUInt32_t*>(buffer);
	words[0] = 0xFFFFFFFF;
	words[3] = 0x03000000;  // RCU version 3 in CDH block attributes field.
	
	file.write(buffer, sizeof(buffer));
	if (! file)
	{
		if (debug) cerr << "ERROR: I/O error when writing to file " << filename << endl;
		return;
	}
	file.close();
}

/**
 * Routine to run a HLT chain with the data checker component to generate output
 * which we can later check. The chain will only test basic functionality of the
 * component.
 */
void RunChainToCheckComponent(bool debug = false)
{
	// Done before to prevent output from AliHLTSystem.
	if (debug)
	{
		AliLog::SetGlobalLogLevel(AliLog::kMaxType);
	}
	else
	{
		AliLog::SetGlobalLogLevel(AliLog::kFatal);
	}
	AliHLTSystem sys;
	sys.LoadComponentLibraries("libAliHLTUtil.so");
	sys.LoadComponentLibraries("libAliHLTTPC.so");
	if (debug)
	{
		sys.SetGlobalLoggingLevel(kHLTLogAll);
	}
	else
	{
		sys.SetGlobalLoggingLevel(kHLTLogNone);
	}
	
	AliHLTConfiguration src(
		"source",
		"FilePublisher",
		"",
		"-datatype 'DDL_RAW ' 'TPC ' -dataspec 0x01010202 -datafile dataCheckerInputTestFile.dat"
	);
	AliHLTConfiguration prc(
		"processor",
		"TPCDataChecker",
		"source",
		"-filter forwardbad -ignoretype"
	);
	AliHLTConfiguration snk(
		"sink",
		"FileWriter",
		"processor",
		"-specfmt -datafile dataCheckerOutputTestFile.dat"
	);
	
	sys.BuildTaskList("sink");
	sys.Run(1); // Run for 1 event.
}

/**
 * Checks the output data generated by the chain.
 * There should be one data block corresponding to the invalid input data block.
 */
bool CheckOutput()
{
	if (gSystem->Exec("test -f dataCheckerOutputTestFile_0x00000000_0x00_TPC:DDL_RAW_0x01010202.dat") != 0)
	{
		cerr << "ERROR: The AliHLTTPCDataCheckerComponent did not generate the expected"
			" output data block when given a corrupt input data block." << endl;
		return false;
	}
	if (gSystem->Exec("diff dataCheckerInputTestFile.dat dataCheckerOutputTestFile_0x00000000_0x00_TPC:DDL_RAW_0x01010202.dat") != 0)
	{
		cerr << "ERROR: The AliHLTTPCDataCheckerComponent forwarded the"
			" wrong data block when checking for errors." << endl;
		return false;
	}
	return true;
}

/**
 * This is the top level testing method which calls individual tests.
 * \returns true if all tests succeeded and false otherwise.
 */
bool testAliHLTTPCDataCheckerComponent(bool debug = false)
{
	if (gClassTable->GetID("AliHLTTPCDataCheckerComponent") < 0)
	{
		gSystem->Load("libAliHLTUtil.so");
	}
	GenerateInputData(debug);
	RunChainToCheckComponent(debug);
	if (! CheckOutput()) return false;
	
	// Cleanup all temporary files generated.
	gSystem->Exec("rm -f dataCheckerInputTestFile.dat dataCheckerOutputTestFile*.dat");
	return true;
}

#ifndef __MAKECINT__

int main(int /*argc*/, const char** /*argv*/)
{
	bool resultOk = testAliHLTTPCDataCheckerComponent();
	if (not resultOk) return 1;
	return 0;
}

#endif // __MAKECINT__

